package com.hp.demo;


import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;


@RestController
@RequestMapping("/executor")
@Slf4j
public class ExecutorUtils {

    @Resource
    private DeviceLogMapper deviceLogMapper;


    // 一个线程最大处理数据量
    private static final int THREAD_COUNT_SIZE = 50000;


    @GetMapping("executeThreadPool")
    public List<DeviceLog> executeThreadPool() {
        //计算表总数
        Integer integer = deviceLogMapper.countDeviceLog();
        log.info("总数为： {}", integer);

        //记录开始时间
        long start = System.currentTimeMillis();


        //new个和表总数一样长的ArrayList
        List<DeviceLog> threadList = new ArrayList<>(integer);

        // 线程数，以5000条数据为一个线程，总数据大小除以5000，再加1
        int round = integer / THREAD_COUNT_SIZE + 1;
        log.info("线程数： {}", round);


        //new一个临时储存List的Map，以线程名为k，用做list排序
        Map<Integer, List<DeviceLog>> temporaryMap = new ConcurrentHashMap<>(round);

        // 程序计数器
        final CountDownLatch count = new CountDownLatch(round);

        // 创建线程
        ExecutorService executor = Executors.newFixedThreadPool(round);

        // 分配数据
        for (int i = 0; i < round; i++) {
            //该线程的查询开始值
            int startLen = i * THREAD_COUNT_SIZE;
            int k = i + 1;
            executor.execute(() -> {
                long partStart = System.currentTimeMillis();
                List<DeviceLog> deviceLogs = deviceLogMapper.subList(startLen);
                //把查出来的List放进临时Map
                temporaryMap.put(k, deviceLogs);
                long partEnd = System.currentTimeMillis();
                log.info("正在处理线程【{}】的数据，数据大小为：{}   耗时：{}ms", k, deviceLogs.size(), partEnd - partStart);
                // 计数器 -1(唤醒阻塞线程)
                count.countDown();
            });
        }
        try {
            // 阻塞线程(主线程等待所有子线程 一起执行业务)
            count.await();
            //结束时间
            long end = System.currentTimeMillis();
            log.info("100万数据查询耗时:{}ms", end - start);
            //通过循环遍历临时map，把map的值有序的放进List里
            temporaryMap.keySet().forEach(k -> threadList.addAll(temporaryMap.get(k)));
        } catch (Exception e) {
            log.error("线程池异常", e);
        } finally {
            //清除临时map，释放内存
            temporaryMap.clear();
            // 终止线程池
            // 启动一次顺序关闭，执行以前提交的任务，但不接受新任务。若已经关闭，则调用没有其他作用。
            executor.shutdown();
        }
        //输出list的长度
        log.info("list长度为：{}", threadList.size());
        return threadList;
    }

    @GetMapping("listAll")
    public List<DeviceLog> listAll() {
        //记录开始时间
        long start = System.currentTimeMillis();
        List<DeviceLog> deviceLogs = deviceLogMapper.listAll();
        //结束时间
        long end = System.currentTimeMillis();
        log.info("{}条数据查询耗时:{}}ms", deviceLogs.size(), end - start);
        return deviceLogs;
    }
}